package com.data.monitoring.service.impl;

import com.data.monitoring.model.entity.FolderStatus;
import com.data.monitoring.model.entity.MonitoredFolders;
import com.data.monitoring.model.entity.MonitoringHistory;
import com.data.monitoring.model.entity.Servers;
import com.data.monitoring.service.FolderStatusService;
import com.data.monitoring.service.MonitoredFoldersService;
import com.data.monitoring.service.MonitoringHistoryService;
import com.data.monitoring.utils.EncryptionUtil;
import com.jcraft.jsch.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class FolderMonitorService {

    @Autowired
    private MonitoredFoldersService folderRepository;

    @Autowired
    private FolderStatusService statusRepository;

    @Autowired
    private MonitoringHistoryService historyRepository;

    @Autowired
    private EncryptionUtil encryptionUtil;

    // 使用ConcurrentHashMap记录每个文件夹的最后检查时间
    private final Map<Long, Long> lastCheckTimeMap = new ConcurrentHashMap<>();

    /**
     * 初始化所有监控任务
     */
    @PostConstruct
    public void initMonitoringTasks() {
        List<MonitoredFolders> folders = folderRepository.findByIsActiveTrue();
        folders.forEach(this::scheduleFolderCheck);
    }

    /**
     * 为单个文件夹创建定时检查任务
     */
    private void scheduleFolderCheck(MonitoredFolders folder) {
        long folderId = folder.getFolderId();
        int interval = folder.getCheckInterval() * 1000; // 转换为毫秒

        // 使用ScheduledExecutorService管理定时任务
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(() -> {
            try {
                long currentTime = System.currentTimeMillis();
                Long lastCheckTime = lastCheckTimeMap.get(folderId);

                // 检查是否到达检查间隔
                if (lastCheckTime == null || (currentTime - lastCheckTime) >= interval) {
                    checkFolder(folder);
                    lastCheckTimeMap.put(folderId, currentTime);
                }
            } catch (Exception e) {
                log.error("监控文件夹异常: {}", folder.getFolderPath(), e);
            }
        }, 0, 1, TimeUnit.MINUTES); // 每分钟检查一次是否到达间隔
    }

    /**
     * 执行实际的文件夹检查
     */
    void checkFolder(MonitoredFolders folder) {
        long startTime = System.currentTimeMillis();
        boolean success = false;
        String errorMsg = null;

        try {
            // 1. 获取最新文件夹信息
            LatestFolderInfo latestInfo = getLatestFolderFromServer(
                    folder.getServers(),
                    folder.getFolderPath()
            );

            // 2. 保存状态记录
            FolderStatus status = new FolderStatus();
            status.setFolders(folder);
            status.setFolderId(folder.getFolderId());
            status.setFolderName(latestInfo.getName());
            status.setFullPath(latestInfo.getFullPath());
            status.setModifyTime(latestInfo.getModifyTime());
            status.setCheckTime(new Date());
            statusRepository.save(status);
            success = true;
        } catch (Exception e) {
            errorMsg = e.getMessage();
            log.error("检查文件夹失败: {}", folder.getFolderPath(), e);
        } finally {
            // 3. 记录监控历史
            MonitoringHistory history = new MonitoringHistory();
            history.setFolders(folder);
            history.setFolderId(folder.getFolderId());
            history.setStatus(success ? "success" : "failed");
            history.setErrorMessage(errorMsg);
            history.setExecutionTime((int) (System.currentTimeMillis() - startTime));
            historyRepository.save(history);
        }
    }

    /**
     * 通过SFTP获取服务器上最新文件夹信息
     */
    private LatestFolderInfo getLatestFolderFromServer(Servers server, String folderPath)
            throws JSchException, SftpException {

        Session session = null;
        ChannelSftp channel = null;

        try {
            // 建立SSH连接
            JSch jsch = new JSch();
            session = jsch.getSession(server.getUsername(), server.getIpAddress(), server.getSshPort());

            if ("password".equals(server.getAuthMethod())) {
                session.setPassword(encryptionUtil.decrypt(server.getAuthKey()));
            } else {
                jsch.addIdentity(server.getAuthKey());
            }

            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();

            // 创建SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();

            // 切换到目标目录
            channel.cd(folderPath);

            // 查找最新文件夹
            Vector<ChannelSftp.LsEntry> list = channel.ls(".");
            ChannelSftp.LsEntry latestEntry = null;
            long latestMtime = 0;

            for (ChannelSftp.LsEntry entry : list) {
                if (entry.getAttrs().isDir() &&
                        !".".equals(entry.getFilename()) &&
                        !"..".equals(entry.getFilename())) {

                    long mtime = entry.getAttrs().getMTime() * 1000L;
                    if (mtime > latestMtime) {
                        latestMtime = mtime;
                        latestEntry = entry;
                    }
                }
            }

            if (latestEntry == null) {
                throw new RuntimeException("目标路径下没有文件夹");
            }

            // 返回结果
            LatestFolderInfo info = new LatestFolderInfo();
            info.setName(latestEntry.getFilename());
            info.setFullPath(folderPath + "/" + latestEntry.getFilename());
            info.setModifyTime(new Date(latestMtime));

            return info;

        } finally {
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
    }

    // 内部类用于返回结果
    @Data
    private static class LatestFolderInfo {
        private String name;
        private String fullPath;
        private Date modifyTime;
    }
}